import { Matrix4 } from "../utils/Matrix4";
import { Util } from "../utils/Util";
import { Vec3 } from "../utils/Vec3";
import { WebGLUtil } from "../utils/WebGLUtil";
import { Render } from "./Render";
import { Webgl3DBase } from "./Webgl3Dbase";
import { IBufferInfo, WebglBase } from "./WebglBase";
/*
 * @Author: Snow
 * @Date: 2021-09-16 15:45:35
 * @Description: 方向光
 */
export class Webgl3DCharFDirectionLight extends Webgl3DBase {

    public override initGLSL(): void {
        this.vsSource = `
            attribute vec4 aVertexPosition;

            //顶点法向量
            attribute vec3 aNamal;

            uniform mat4 uViewMatrix;

            uniform mat4 uWorldInverseTranspose;

            varying vec3 vNamal;

            void main() {
                gl_Position = uViewMatrix * aVertexPosition;
                
                //法向量变换
                vNamal = mat3(uWorldInverseTranspose) * aNamal;
            }
        `;

        this.fsSource = `
            //设置浮点精度
            precision mediump float;
            
            varying vec3 vNamal;

            uniform vec4 uColor;
            // 方向光 的反方向
            uniform vec3 uDirectionLight;

            void main() {
                vec3 namal = normalize(vNamal);
                float light = dot(namal,uDirectionLight);
                gl_FragColor = uColor;
                gl_FragColor.rgb *= light;
            }
        `;
    }

    public override initUITools(): void {
        const gl = Render.GL;
        let translation = [-150, 0, -360];
        let angle = 60;
        let scale = [1, 1];

        // Setup a ui.
        const webglLessonsUI = (window as any).webglLessonsUI;
        webglLessonsUI.setupSlider("#x", { value: translation[0], slide: this.onUpateSlide(this, "x"), min: -gl.canvas.width / 2, max: gl.canvas.width / 2 });
        webglLessonsUI.setupSlider("#y", { value: translation[1], slide: this.onUpateSlide(this, "y"), min: -gl.canvas.height / 2, max: gl.canvas.height / 2 });
        webglLessonsUI.setupSlider("#z", { value: 0, slide: this.onUpateSlide(this, "z"), max: -1, min: -1000, step: 1, precision: 0 });
        webglLessonsUI.setupSlider("#angle", { value: angle, slide: this.onUpateSlide(this, "angle"), max: 360 });
        webglLessonsUI.setupSlider("#scaleX", { value: scale[0], slide: this.onUpateSlide(this, "scaleX"), min: -5, max: 5, step: 0.01, precision: 2 });
        webglLessonsUI.setupSlider("#scaleY", { value: scale[1], slide: this.onUpateSlide(this, "scaleY"), min: -5, max: 5, step: 0.01, precision: 2 });
        this.createSlider("scaleZ", { value: scale[1], slide: this.onUpateSlide(this, "scaleZ"), min: -5, max: 5, step: 0.01, precision: 2 })
        this.createSlider("rotationX", { value: 0, slide: this.onUpateSlide(this, "rotationX"), min: 0, max: 360, step: 1, precision: 0 })
        this.createSlider("rotationY", { value: 0, slide: this.onUpateSlide(this, "rotationY"), min: 0, max: 360, step: 1, precision: 0 })
        this.createSlider("rotationZ", { value: 0, slide: this.onUpateSlide(this, "rotationZ"), min: 0, max: 360, step: 1, precision: 0 })

        this.uiParam = { x: -150, y: 0, z: -360, rotationX: 0, rotationY: 0, rotationZ: 0, scaleX: 1, scaleY: 1, scaleZ: 1, anchorX: 0, anchorY: 0, angle: angle };
    }

    public override initBuffer(): IBufferInfo {
        const gl = Render.GL;
        const vPos = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, vPos);
        const vertices = [
            // left column front
            0, 0, 0,
            0, 150, 0,
            30, 0, 0,
            0, 150, 0,
            30, 150, 0,
            30, 0, 0,

            // top rung front
            30, 0, 0,
            30, 30, 0,
            100, 0, 0,
            30, 30, 0,
            100, 30, 0,
            100, 0, 0,

            // middle rung front
            30, 60, 0,
            30, 90, 0,
            67, 60, 0,
            30, 90, 0,
            67, 90, 0,
            67, 60, 0,

            // left column back
            0, 0, 30,
            30, 0, 30,
            0, 150, 30,
            0, 150, 30,
            30, 0, 30,
            30, 150, 30,

            // top rung back
            30, 0, 30,
            100, 0, 30,
            30, 30, 30,
            30, 30, 30,
            100, 0, 30,
            100, 30, 30,

            // middle rung back
            30, 60, 30,
            67, 60, 30,
            30, 90, 30,
            30, 90, 30,
            67, 60, 30,
            67, 90, 30,

            // top
            0, 0, 0,
            100, 0, 0,
            100, 0, 30,
            0, 0, 0,
            100, 0, 30,
            0, 0, 30,

            // top rung right
            100, 0, 0,
            100, 30, 0,
            100, 30, 30,
            100, 0, 0,
            100, 30, 30,
            100, 0, 30,

            // under top rung
            30, 30, 0,
            30, 30, 30,
            100, 30, 30,
            30, 30, 0,
            100, 30, 30,
            100, 30, 0,

            // between top rung and middle
            30, 30, 0,
            30, 60, 30,
            30, 30, 30,
            30, 30, 0,
            30, 60, 0,
            30, 60, 30,

            // top of middle rung
            30, 60, 0,
            67, 60, 30,
            30, 60, 30,
            30, 60, 0,
            67, 60, 0,
            67, 60, 30,

            // right of middle rung
            67, 60, 0,
            67, 90, 30,
            67, 60, 30,
            67, 60, 0,
            67, 90, 0,
            67, 90, 30,

            // bottom of middle rung.
            30, 90, 0,
            30, 90, 30,
            67, 90, 30,
            30, 90, 0,
            67, 90, 30,
            67, 90, 0,

            // right of bottom
            30, 90, 0,
            30, 150, 30,
            30, 90, 30,
            30, 90, 0,
            30, 150, 0,
            30, 150, 30,

            // bottom
            0, 150, 0,
            0, 150, 30,
            30, 150, 30,
            0, 150, 0,
            30, 150, 30,
            30, 150, 0,

            // left side
            0, 0, 0,
            0, 0, 30,
            0, 150, 30,
            0, 0, 0,
            0, 150, 30,
            0, 150, 0
        ];


        ///模型转型顺序是 先平移  再旋转  再缩放
        ///视图转换顺序相反

        let mat = Matrix4.rotateX(Math.PI);
        mat = Matrix4.multiply(mat, Matrix4.translation(-50, -75, -15));

        for (let ii = 0; ii < vertices.length; ii += 3) {
            //let vector = Matrix4.transformPoint(mat, [vertices[ii + 0], vertices[ii + 1], vertices[ii + 2], 1]);
            let vector = Matrix4.multiplyPoint(mat, [vertices[ii + 0], vertices[ii + 1], vertices[ii + 2], 1]);
            vertices[ii + 0] = vector[0];
            vertices[ii + 1] = vector[1];
            vertices[ii + 2] = vector[2];
        }

        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);


        var normals = new Float32Array([
            // left column front
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
  
            // top rung front
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
  
            // middle rung front
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
            0, 0, 1,
  
            // left column back
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
  
            // top rung back
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
  
            // middle rung back
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
            0, 0, -1,
  
            // top
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
  
            // top rung right
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
  
            // under top rung
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
  
            // between top rung and middle
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
  
            // top of middle rung
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
            0, 1, 0,
  
            // right of middle rung
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
  
            // bottom of middle rung.
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
  
            // right of bottom
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
            1, 0, 0,
  
            // bottom
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
            0, -1, 0,
  
            // left side
            -1, 0, 0,
            -1, 0, 0,
            -1, 0, 0,
            -1, 0, 0,
            -1, 0, 0,
            -1, 0, 0]);
        

        const vColorBuffer = gl.createBuffer();
        const indexsBuffer = gl.createBuffer();

        const vNormalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER,vNormalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER,normals,gl.STATIC_DRAW);


        this.bufferInfo = { vPos: vPos, vColor: vColorBuffer, indices: indexsBuffer ,vNormal:vNormalBuffer};
        return this.bufferInfo;
    }

    public override draw(param?: any): void {
        const gl = Render.GL;
        WebGLUtil.resizeCanvasToMatchDisplaySize(gl);

        gl.clearColor(1.0, 1.0, 1.0, 1.0);
        gl.enable(gl.CULL_FACE); //提出反三角形
        gl.enable(gl.DEPTH_TEST);
        //gl.clearDepth(1.0);
        //gl.enable(gl.DEPTH_TEST);
        //gl.depthFunc(gl.LEQUAL);
        // 清空画布和深度缓冲
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        //gl.clear(gl.COLOR_BUFFER_BIT);

        //this.updateMatrix();
        //上传顶点数据到shader
        {
            const numComponents = 3;  // pull out 3 values per iteration
            const type = gl.FLOAT;    // the data in the buffer is 32bit floats
            const normalize = false;  // don't normalize
            const stride = 0;         // how many bytes to get from one set of values to the next
            // 0 = use type and numComponents above
            const offset = 0;         // how many bytes inside the buffer to start from
            gl.enableVertexAttribArray(
                this.programInfo.attributes.aVertexPosition);
            gl.bindBuffer(gl.ARRAY_BUFFER, this.bufferInfo.vPos);
            gl.vertexAttribPointer(
                this.programInfo.attributes.aVertexPosition,
                numComponents,
                type,
                normalize,
                stride,
                offset);

        }

        //上传顶点法向量
        {
            const numComponents = 3;  // pull out 3 values per iteration
            const type = gl.FLOAT;    // the data in the buffer is 32bit floats
            const normalize = false;  // don't normalize
            const stride = 0;         // how many bytes to get from one set of values to the next
            // 0 = use type and numComponents above
            const offset = 0;         // how many bytes inside the buffer to start from
            let aNamal = gl.getAttribLocation(this.shaderProgram,"aNamal")
            gl.enableVertexAttribArray(
                aNamal);
            gl.bindBuffer(gl.ARRAY_BUFFER, this.bufferInfo.vNormal);
            gl.vertexAttribPointer(
                aNamal,
                numComponents,
                type,
                normalize,
                stride,
                offset);
        }

        ////上传顶点颜色
        // {
        // 	gl.enableVertexAttribArray(this.programInfo.attributes.aVertexColor);	
        // 	gl.bindBuffer(gl.ARRAY_BUFFER,this.bufferInfo.vColor);
        // 	gl.vertexAttribPointer(
        // 		this.programInfo.attributes.aVertexColor,
        // 		4,
        // 		gl.FLOAT,
        // 		false,
        // 		0,
        //         0);
        // }

        // Tell WebGL which indices to use to index the vertices
        //gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.bufferInfo.indices);

        // Tell WebGL to use our program when drawing\
        gl.useProgram(this.shaderProgram);


        let x = this.uiParam["x"];
        let y = this.uiParam["y"];
        let z = this.uiParam["z"];
        let rotationX = this.uiParam["rotationX"];
        let rotationY = this.uiParam["rotationY"];
        let rotationZ = this.uiParam["rotationZ"];

        let scaleX = this.uiParam["scaleX"];
        let scaleY = this.uiParam["scaleY"];
        let scaleZ = this.uiParam["scaleZ"];

        let anchorX = this.uiParam["anchorX"];
        let anchorY = this.uiParam["anchorY"];

        let angle = this.uiParam["angle"];

        let angleInRadiansX = rotationX * Math.PI / 180;

        let angleInRadiansY = rotationY * Math.PI / 180;

        let angleInRadiansZ = rotationZ * Math.PI / 180;


        let camera = [100, 150, 200];
        let target = [0, 35, 0];
        let up = [0, 1, 0];



        let lookAtMat = Matrix4.lookAt(camera, target, up);


        let projectionMatrix: number[] = Matrix4.perspective(Util.degToRad(angle), gl.canvas.width / gl.canvas.height, 1, 2000);

        projectionMatrix = Matrix4.multiply(projectionMatrix, Matrix4.invert(lookAtMat));

        
        let  worldInverseTranspose = Matrix4.create();
        
        let matrix: number[] = Matrix4.create();



        let rotationYMatrix: number[] = Matrix4.rotateY(angleInRadiansY);

         worldInverseTranspose = Matrix4.multiply( worldInverseTranspose,rotationYMatrix);
         worldInverseTranspose = Matrix4.invert( worldInverseTranspose);
         worldInverseTranspose = Matrix4.transpose( worldInverseTranspose);


        matrix = Matrix4.multiply(matrix, projectionMatrix);
        matrix = Matrix4.multiply(matrix, rotationYMatrix);



        gl.uniformMatrix4fv(
            this.programInfo.uniforms.uViewMatrix,
            false,
            new Float32Array(matrix));

        let uColorLoc = gl.getUniformLocation(this.shaderProgram, "uColor");
        //上传颜色
        gl.uniform4fv(
            uColorLoc,
            new Float32Array([0.2, 1, 0.2, 1]));
        
        let uDirectionLight = gl.getUniformLocation(this.shaderProgram, "uDirectionLight");
        //上传光源
        gl.uniform3fv(
            uDirectionLight,
            new Float32Array(Vec3.normalize([0.5, 0.7, 1])));
        
        //上传世界矩阵
        let worldInverseTransposeLoc = gl.getUniformLocation(this.shaderProgram, "uWorldInverseTranspose");
        //上传光源
        gl.uniformMatrix4fv(
            worldInverseTransposeLoc,
            false,
            new Float32Array( worldInverseTranspose));
        

        gl.drawArrays(gl.TRIANGLES, 0, 96);
    }
}